package io.kiki.sba.registry.server.shared.remoting;

import io.kiki.sba.registry.api.Channel;
import io.kiki.sba.registry.api.ChannelHandler;
import io.kiki.sba.registry.common.model.Node;
import io.kiki.sba.registry.store.jdbc.repository.impl.ClientManagerAddressJdbcRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public abstract class AbstractChannelHandler<T> implements ChannelHandler<T> {
    private static final Logger logger = LoggerFactory.getLogger(ClientManagerAddressJdbcRepository.class);


    @Override
    public void connected(Channel channel) {
        logger.info("{} node connected, channel {}", getConnectNodeType(), channel);
    }

    @Override
    public void disconnected(Channel channel) {
        logger.info("{} node disconnected, channel {}", getConnectNodeType(), channel);
    }

    protected abstract Node.NodeType getConnectNodeType();

    @Override
    public void exceptionCaught(Channel channel, T message, Throwable exception) {
        logger.error("{} caughtException, channel {}, msg={}", getConnectNodeType(), channel, message, (Throwable) exception);
    }

    @Override
    public void messageReceived(Channel channel, T message) {
        // only support as async
        throw new UnsupportedOperationException();
    }

    @Override
    public Object messageReply(Channel channel, T request) {
        try {

            logRequest(channel, request);
            checkParam(request);
            return doHandle(channel, request);
        } catch (Throwable e) {
            logger.error("[{}] handle request failed", getClassName(), e);
            return buildFailedResponse(e.getMessage());
        } finally {

        }
    }

    /**
     * check params if valid
     */
    public void checkParam(T request) {
    }


    public abstract Object doHandle(Channel channel, T request);

    /**
     * build failed response
     */
    public Object buildFailedResponse(String msg) {
        throw new RuntimeException(msg);
    }


    protected void logRequest(Channel channel, T request) {
        if (logger.isInfoEnabled()) {
            StringBuilder sb = new StringBuilder(256);
            sb.append("[").append(getClassName()).append("] ");
            sb.append("Remote:").append(RemotingHelper.getChannelRemoteAddress(channel)).append(" Request:").append(request);
            logger.info(sb.toString());
        }
    }

    /**
     * get simple name of this class
     */
    private String getClassName() {
        return this.getClass().getSimpleName();
    }

    @Override
    public HandlerType getHandlerType() {
        return HandlerType.PROCESSER;
    }
}
